/*
    This file is part of MP3DecodeDLL for Symbian.

    MP3DecodeDLL for Symbian
    Copyright (C) 2004 Denis Mingulov <denis@mingulov.com>

    MP3DecodeDLL for Symbian is free software; you can redistribute
    it and/or modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.

    MP3DecodeDLL for Symbian is distributed in the hope that it
    will be useful, but WITHOUT ANY WARRANTY; without even the implied
    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MP3DecodeDLL for Symbian; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include "string.h"
#include "MP3Decode.h"

#define BUFFERSIZE 512
#include "math.h"

CMP3Decode::CMP3Decode() : bFileOpened(EFalse), iFileSession(NULL), iResampleRate(8000)
{
	iMediaOffset = 0;
	iMediaRealSize = 0;
}

CMP3Decode::~CMP3Decode()
{
	Close();
	delete iInputBuf;
}

CMP3Decode * CMP3Decode::NewL()
{
    CMP3Decode* iMP3Decode = CMP3Decode::NewLC();
    CleanupStack::Pop(iMP3Decode);
    return iMP3Decode;

}

CMP3Decode * CMP3Decode::NewLC()
{
	CMP3Decode* iMP3Decode = new (ELeave) CMP3Decode();
    CleanupStack::PushL(iMP3Decode);
    iMP3Decode->ConstructL();
    return iMP3Decode;

}

void CMP3Decode::ConstructL()
{
	iInputBuf = new TPtr8((TUint8*)InputBuffer2, INPUT_BUFFER_SIZE, INPUT_BUFFER_SIZE);
}

TInt CMP3Decode::Open(RFs &aFileServer, const TDesC &aFileName, int mediaoffset, int mediarealsize) 
{
	iFileSession = &aFileServer;
	strFileNameMP3.Copy(aFileName);
	
	//william
	iMediaOffset = mediaoffset;
	iMediaRealSize = mediarealsize;

	TInt iErr = InitMP3();

	if(iErr)
		bFileOpened = EFalse;
	else
		bFileOpened = ETrue;

	return iErr;
}

TInt CMP3Decode::Close()
{
	if(bFileOpened)
	{
		CloseMP3();
	}
	return 0;
}

TInt CMP3Decode::SetResampleRate(TInt aResampleRate)
{
	iResampleRate = aResampleRate;
	return 0;
}

TInt CMP3Decode::SetEqualizer (TInt aEq60, TInt aEq170, TInt aEq310, TInt aEq600, TInt aEq1K, TInt aEq3K, TInt aEq6K, TInt aEq12K, TInt aEq14K, TInt aEq16K, TInt aEqZero, TInt aEqDiv)
{
	// 60, 170, 310, 600, 1K, 3K
	iEqualizer[0] = mad_f_tofixed (pow (10,((double)(aEq60-aEqZero))/(double)aEqDiv));
	iEqualizer[1] = mad_f_tofixed (pow (10,((double)(aEq170-aEqZero))/(double)aEqDiv));
	iEqualizer[2] = mad_f_tofixed (pow (10,((double)(aEq310-aEqZero))/(double)aEqDiv));
	iEqualizer[3] = mad_f_tofixed (pow (10,((double)(aEq600-aEqZero))/(double)aEqDiv));
	iEqualizer[4] = mad_f_tofixed (pow (10,((double)(aEq1K-aEqZero))/(double)aEqDiv));
	iEqualizer[5] = mad_f_tofixed (pow (10,((double)(aEq3K-aEqZero))/(double)aEqDiv));
	//6K
	iEqualizer[6] = mad_f_tofixed (pow (10,((double)(aEq6K-aEqZero))/(double)aEqDiv));
	iEqualizer[7] = iEqualizer[6];
	//12K
	iEqualizer[8] = mad_f_tofixed (pow (10,((double)(aEq12K-aEqZero))/(double)aEqDiv));
	iEqualizer[9] = iEqualizer[8];
	iEqualizer[10] = iEqualizer[8];
	iEqualizer[11] = iEqualizer[8];
	//14K
	iEqualizer[12] = mad_f_tofixed (pow (10,((double)(aEq14K-aEqZero))/(double)aEqDiv));
	iEqualizer[13] = iEqualizer[12];
	iEqualizer[14] = iEqualizer[12];
	iEqualizer[15] = iEqualizer[12];
	iEqualizer[16] = iEqualizer[12];
	iEqualizer[17] = iEqualizer[12];
	iEqualizer[18] = iEqualizer[12];
	iEqualizer[19] = iEqualizer[12];
	//16K
	iEqualizer[20] = mad_f_tofixed (pow (10,((double)(aEq16K-aEqZero))/(double)aEqDiv));
	iEqualizer[21] = iEqualizer[20];
	iEqualizer[22] = iEqualizer[20];
	iEqualizer[23] = iEqualizer[20];
	iEqualizer[24] = iEqualizer[20];
	iEqualizer[25] = iEqualizer[20];
	iEqualizer[26] = iEqualizer[20];
	iEqualizer[27] = iEqualizer[20];
	iEqualizer[28] = iEqualizer[20];
	iEqualizer[29] = iEqualizer[20];
	iEqualizer[30] = iEqualizer[20];
	iEqualizer[31] = iEqualizer[20];

	return 0;
}

TInt CMP3Decode::GetFileLength()
{
	TInt iLength=0;
	
	if(iFile.Size(iLength)==KErrNone)
	{
		if(iMediaRealSize != 0)
			return iMediaRealSize;//william
		else
			return iLength;
	}
	else
	{
		return 0;
	}
}

TInt CMP3Decode::GetFilePosition()
{
	TInt iPos=0;
	if(iFile.Seek(ESeekCurrent, iPos)==KErrNone)
	{
		return iPos;
	}
	else
	{
		return 0;
	}
}

TInt CMP3Decode::InitMP3()
{
	TInt iErr=0;
	iErr = iFile.Open(*iFileSession,strFileNameMP3,EFileRead|EFileShareAny);//EFileShareReadersOnly);
	//william
	int pos = iMediaOffset;
	iFile.Seek(ESeekStart, pos);

	SetEqualizer(100,100,100,100,100,100,100,100,100,100,100,20);

	/* First the structures used by libmad must be initialized. */
	mad_stream_init(&Stream);
	mad_frame_init(&Frame);
	mad_synth_init(&Synth);
	mad_timer_reset(&Timer);

	Status=0;
	iOutputBufferCurrent=0;

	return iErr;
}

TInt CMP3Decode::CloseMP3()
{
	iFile.Close();

	/* Mad is no longer used, the structures that were initialized must
     * now be cleared.
	 */
	mad_synth_finish(&Synth);
	mad_frame_finish(&Frame);
	mad_stream_finish(&Stream);

	iMediaOffset = 0; //william
	iMediaRealSize = 0; //william
	return 0;
}

TInt CMP3Decode::DecodeOneFrame(TDes& aBuffer)
{
	int iErr = DecodeOneFrameLow();
	if(iErr==0&&iOutputBufferLength[iOutputBufferCurrent]==0)
	{
		iErr = DecodeOneFrameLow();
	}
	aBuffer.Copy((const TUint16*)OutputBuffer[iOutputBufferCurrent],iOutputBufferLength[iOutputBufferCurrent]);
	return iErr;
}

int CMP3Decode::DecodeOneFrameLow()
// based on sources of 
// madplay - MPEG audio decoder and player
// Copyright (C) 2000-2004 Robert Leslie


{
	TInt16 *OutputPtr=OutputBuffer[iOutputBufferCurrent];
	TInt16 *OutputBufferEnd=OutputPtr+OUTPUT_BUFFER_SIZE;
	int iCycle=0;

	iOutputBufferLength[iOutputBufferCurrent]=0;

	for(iCycle=0;iCycle<1;iCycle++)
	{
		/* The input bucket must be filled if it becomes empty or if
		 * it's the first execution of the loop.
		 */
		if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
		{
			size_t			ReadSize, ReadSize2,
							Remaining;
			unsigned char	*ReadStart;

			/* {2} libmad may not consume all bytes of the input
			 * buffer. If the last frame in the buffer is not wholly
			 * contained by it, then that frame's start is pointed by
			 * the next_frame member of the Stream structure. This
			 * common situation occurs when mad_frame_decode() fails,
			 * sets the stream error code to MAD_ERROR_BUFLEN, and
			 * sets the next_frame pointer to a non NULL value. (See
			 * also the comment marked {4} bellow.)
			 *
			 * When this occurs, the remaining unused bytes must be
			 * put back at the beginning of the buffer and taken in
			 * account before refilling the buffer. This means that
			 * the input buffer must be large enough to hold a whole
			 * frame at the highest observable bit-rate (currently 448
			 * kb/s). XXX=XXX Is 2016 bytes the size of the largest
			 * frame? (448000*(1152/32000))/8
			 */
			if(Stream.next_frame!=NULL)
			{
//				iFilePos+=Stream.next_frame-Stream.buffer;
				Remaining=Stream.bufend-Stream.next_frame;
				memmove(InputBuffer,Stream.next_frame,Remaining);
				ReadStart=InputBuffer+Remaining;
				ReadSize=INPUT_BUFFER_SIZE-Remaining;

/*				ReadSize=INPUT_BUFFER_SIZE,
					ReadStart=InputBuffer,
					Remaining=0;*/
			}
			else
				ReadSize=INPUT_BUFFER_SIZE,
					ReadStart=InputBuffer,
					Remaining=0;
			
			/* Fill-in the buffer. If an error occurs print a message
			 * and leave the decoding loop. If the end of stream is
			 * reached we also leave the loop but the return status is
			 * left untouched.
			 */
//			fprintf(stderr,"file pos: %x\n",iFilePos);
//			fseek(fr,iFilePos,SEEK_SET);
			iInputBuf->SetLength(INPUT_BUFFER_SIZE);
			iFile.Read(*iInputBuf,ReadSize);
//			ReadSize=fread(ReadStart,1,ReadSize,fr);
			ReadSize2=ReadSize;
			ReadSize=iInputBuf->Length();

			memmove(ReadStart,InputBuffer2,ReadSize);

			if(ReadSize<=0)
			{
//				if(ferror(fr))
				{
//					fprintf(stderr,"%s: read error on bitstream (%s)\n",
//							ProgName,strerror(errno));
//					Status=1;
				}
//				if(feof(fr))
					;//fprintf(stderr,"%s: end of input stream\n",ProgName);
				return 1;
//				break;
			}

			/* {3} When decoding the last frame of a file, it must be
			 * followed by MAD_BUFFER_GUARD zero bytes if one wants to
			 * decode that last frame. When the end of file is
			 * detected we append that quantity of bytes at the end of
			 * the available data. Note that the buffer can't overflow
			 * as the guard size was allocated but not used the the
			 * buffer managment code. (See also the comment marked
			 * {1}.)
			 *
			 * In a message to the mad-dev mailing list on May 29th,
			 * 2001, Rob leslie explains the guard zone as follows:
			 * 
			 *    "The reason for MAD_BUFFER_GUARD has to do with the
			 *    way decoding is performed. In Layer III, Huffman
			 *    decoding may inadvertently read a few bytes beyond
			 *    the end of the buffer in the case of certain invalid
			 *    input. This is not detected until after the fact. To
			 *    prevent this from causing problems, and also to
			 *    ensure the next frame's main_data_begin pointer is
			 *    always accessible, MAD requires MAD_BUFFER_GUARD
			 *    (currently 8) bytes to be present in the buffer past
			 *    the end of the current frame in order to decode the
			 *    frame."
			 */
//			if(feof(fr))
			if(ReadSize!=ReadSize2)
			{
				memset(ReadStart+ReadSize,0,MAD_BUFFER_GUARD);
				ReadSize+=MAD_BUFFER_GUARD;
			}

			/* Pipe the new buffer content to libmad's stream decoder
             * facility.
			 */
			mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining);
			Stream.error=MAD_ERROR_NONE;
		}

		/* Decode the next mpeg frame. The streams is read from the
		 * buffer, its constituents are break down and stored the the
		 * Frame structure, ready for examination/alteration or PCM
		 * synthesis. Decoding options are carried in the Frame
		 * structure from the Stream structure.
		 *
		 * Error handling: mad_frame_decode() returns a non zero value
		 * when an error occurs. The error condition can be checked in
		 * the error member of the Stream structure. A mad error is
		 * recoverable or fatal, the error status is checked with the
		 * MAD_RECOVERABLE macro.
		 *
		 * {4} When a fatal error is encountered all decoding
		 * activities shall be stopped, except when a MAD_ERROR_BUFLEN
		 * is signaled. This condition means that the
		 * mad_frame_decode() function needs more input to achieve
		 * it's work. One shall refill the buffer and repeat the
		 * mad_frame_decode() call. Some bytes may be left unused at
		 * the end of the buffer if those bytes forms an incomplete
		 * frame. Before refilling, the remainign bytes must be moved
		 * to the begining of the buffer and used for input for the
		 * next mad_frame_decode() invocation. (See the comments marked
		 * {2} earlier for more details.)
		 *
		 * Recoverable errors are caused by malformed bit-streams, in
		 * this case one can call again mad_frame_decode() in order to
		 * skip the faulty part and re-sync to the next frame.
		 */
		if(mad_frame_decode(&Frame,&Stream))
		{
			if(MAD_RECOVERABLE(Stream.error))
			{
//				char s[300];
//				sprintf(s,"%s: recoverable frame level error (%s)\n",
//						ProgName,MadErrorString(&Stream));
//				fprintf(stderr,"%s: recoverable frame level error (%s)\n",
//						ProgName,MadErrorString(&Stream));
//				fflush(stderr);
				return 0;//Stream.error;
			}
			else
				if(Stream.error==MAD_ERROR_BUFLEN)
					return 0;//MAD_ERROR_BUFLEN;
				else
				{
//					fprintf(stderr,"%s: unrecoverable frame level error (%s).\n",
//							ProgName,MadErrorString(&Stream));
					Status=1;
					return -1;
//					break;
				}
		}

		/* The characteristics of the stream's first frame is printed
		 * on stderr. The first frame is representative of the entire
		 * stream.
		 */
		if(FrameCount==0)
			;
//			if(PrintFrameInfo(stderr,&Frame.header))
//			{
//				Status=1;
//				return 1;
//				break;
//			}

		/* Accounting. The computed frame duration is in the frame
		 * header structure. It is expressed as a fixed point number
		 * whole data type is mad_timer_t. It is different from the
		 * samples fixed point format and unlike it, it can't directly
		 * be added or substracted. The timer module provides several
		 * functions to operate on such numbers. Be careful there, as
		 * some functions of mad's timer module receive some of their
		 * mad_timer_t arguments by value!
		 */
		FrameCount++;
		mad_timer_add(&Timer,Frame.header.duration);

		/* Between the frame decoding and samples synthesis we can
		 * perform some operations on the audio data. We do this only
		 * if some processing was required. Detailed explanations are
		 * given in the ApplyFilter() function.
		 */
//		if(DoFilter)
			ApplyFilter(&Frame);
				
		/* Once decoded the frame is synthesized to PCM samples. No errors
		 * are reported by mad_synth_frame();
		 */
		Frame.options |= MAD_OPTION_IGNORECRC;
		if(Frame.header.samplerate>=iResampleRate*2)
			Frame.options |= MAD_OPTION_HALFSAMPLERATE;

		mad_synth_frame(&Synth,&Frame);

		int samplerate=Synth.pcm.samplerate;
		{
			resample_state resample;
			resample_init(&resample,samplerate,iResampleRate);
			int iLen=resample_block(&resample, Synth.pcm.length, Synth.pcm.samples[0], &OutputPtr[iOutputBufferLength[iOutputBufferCurrent]]);
			iOutputBufferLength[iOutputBufferCurrent]+=iLen;
//			iSoundBuf2[iOutputBufferCurrent]->SetLength(iOutputBufferLength[iOutputBufferCurrent]*2);

		}

		/* Synthesized samples must be converted from mad's fixed
		 * point number to the consumer format. Here we use unsigned
		 * 16 bit big endian integers on two channels. Integer samples
		 * are temporarily stored in a buffer that is flushed when
		 * full.
		 */
//		int i;
//		iOutputBufferLength[iOutputBufferCurrent]=Synth.pcm.length;
//		iSoundBuf2[iOutputBufferCurrent]->SetLength(iOutputBufferLength[iOutputBufferCurrent]*2);
//		for(i=0;i<Synth.pcm.length;i++)
//		{
//			signed short	Sample;

			/* Left channel */
//			Sample=MP3FixedToShort/*MadFixedToSshort*/(Synth.pcm.samples[0][i]);
//			*(OutputPtr++)=Sample;
//			*(OutputPtr++)=(Sample>>0)&0xff;
//			*(OutputPtr++)=(Sample>>8)&0xff;

			/* Right channel. If the decoded stream is monophonic then
			 * the right output channel is the same as the left one.
			 */
//			if(MAD_NCHANNELS(&Frame.header)==2)
//				Sample=MP3FixedToShort/*MadFixedToSshort*/(Synth.pcm.samples[1][i]);
//			*(OutputPtr++)=Sample;
//			*(OutputPtr++)=(Sample>>0)&0xff;
//			*(OutputPtr++)=(Sample>>8)&0xff;

			/* Flush the output buffer if it is full. */
/*			if(OutputPtr==OutputBufferEnd)
			{
				if(fwrite(OutputBuffer,1,OUTPUT_BUFFER_SIZE,fw)!=OUTPUT_BUFFER_SIZE)
				{
//					fprintf(stderr,"%s: PCM write error (%s).\n",
//							ProgName,strerror(errno));
					Status=2;
					return 1;
//					break;
				}
				OutputPtr=OutputBuffer;
			}*/
//		}
	}
	return 0;
}

void CMP3Decode::ApplyFilter(mad_frame *Frame)
{
//mono
	if (Frame->header.mode != MAD_MODE_SINGLE_CHANNEL) 
	{
	    unsigned int ns, s, sb;
	    mad_fixed_t left, right;

		ns = MAD_NSBSAMPLES(&Frame->header);

		for (s = 0; s < ns; ++s) 
		{
			for (sb = 0; sb < 32; ++sb) 
			{
				left  = Frame->sbsample[0][s][sb];
				right = Frame->sbsample[1][s][sb];

				Frame->sbsample[0][s][sb] = (left + right) / 2;
//				Frame->sbsample[0][s][sb] = mad_f_div(left + right,mad_f_tofixed(2));
//				Frame->sbsample[0][s][sb] = Frame->sbsample[1][s][sb];
				// frame->sbsample[1][s][sb] = 0; 
			}
		}

		Frame->header.mode = MAD_MODE_SINGLE_CHANNEL;
	}
	//Frame->header.mode = MAD_MODE_SINGLE_CHANNEL;


	int	Channel,
		Sample,
		Samples,
		SubBand;
	
	/* There is two application loops, each optimized for the number
	 * of audio channels to process. The first alternative is for
	 * two-channel frames, the second is for mono-audio.
	 */
	mad_fixed_t *Filter=iEqualizer;
	Samples=MAD_NSBSAMPLES(&Frame->header);
	if(Frame->header.mode!=MAD_MODE_SINGLE_CHANNEL)
		for(Channel=0;Channel<2;Channel++)
			for(Sample=0;Sample<Samples;Sample++)
				for(SubBand=0;SubBand<32;SubBand++)
					Frame->sbsample[Channel][Sample][SubBand]=
						mad_f_mul(Frame->sbsample[Channel][Sample][SubBand],
								  Filter[SubBand]);
	else
		for(Sample=0;Sample<Samples;Sample++)
			for(SubBand=0;SubBand<32;SubBand++)
				Frame->sbsample[0][Sample][SubBand]=
					mad_f_mul(Frame->sbsample[0][Sample][SubBand],
							  Filter[SubBand]);

}

signed int CMP3Decode::MP3FixedToShort(mad_fixed_t sample)
{
	/* round */
	sample += (1L << (MAD_F_FRACBITS - 16));

	/* clip */
	if (sample >= MAD_F_ONE)	
		sample = MAD_F_ONE - 1;
	else if (sample < -MAD_F_ONE)
		sample = -MAD_F_ONE;

	/* quantize */
	return sample >> (MAD_F_FRACBITS + 1 - 16);
}

int CMP3Decode::resample_init(resample_state *state, unsigned int oldrate, unsigned int newrate)
{
	mad_fixed_t ratio;

	if (newrate == 0)
		return -1;

	ratio = mad_f_div(oldrate, newrate);
	if (ratio <= 0 || ratio > MAX_RESAMPLEFACTOR * MAD_F_ONE)
		return -1;

	state->ratio = ratio;

	state->step = 0;
	state->last = 0;

	return 0;
}

unsigned int CMP3Decode::resample_block(resample_state *state, unsigned int nsamples, const mad_fixed_t *old, TInt16 *newb)
{
	mad_fixed_t const *end;
	TInt16 *begin;

	/*
	 * This resampling algorithm is based on a linear interpolation, which is
     * not at all the best sounding but is relatively fast and efficient.
     *
     * A better algorithm would be one that implements a bandlimited
     * interpolation.
     */

	if (state->ratio == MAD_F_ONE) 
	{
		unsigned int i;
		for(i=0;i<nsamples;i++)
		{
			signed short	Sample;

			/* Left channel */
			Sample=MP3FixedToShort/*MadFixedToSshort*/(old[i]);
			(*newb++)=Sample;
		}
//	memcpy(newb, old, nsamples * sizeof(mad_fixed_t));
//    return nsamples;
	}

	end   = old + nsamples;
	begin = newb;

	if (state->step < 0) 
	{
		state->step = mad_f_fracpart(-state->step);

		while (state->step < MAD_F_ONE) 
		{
			*newb++ = MP3FixedToShort (state->step ? state->last + mad_f_mul(*old - state->last, state->step) : state->last);

			state->step += state->ratio;
			if (((state->step + 0x00000080L) & 0x0fffff00L) == 0)
				state->step = (state->step + 0x00000080L) & ~0x0fffffffL;
		}

		state->step -= MAD_F_ONE;
	}

	while (end - old > 1 + mad_f_intpart(state->step)) 
	{
		old        += mad_f_intpart(state->step);
		state->step = mad_f_fracpart(state->step);

		*newb++ = MP3FixedToShort (state->step ? *old + mad_f_mul(old[1] - old[0], state->step) : *old);

		state->step += state->ratio;
		if (((state->step + 0x00000080L) & 0x0fffff00L) == 0)
			state->step = (state->step + 0x00000080L) & ~0x0fffffffL;
	}

	if (end - old == 1 + mad_f_intpart(state->step)) 
	{
		state->last = end[-1];
		state->step = -state->step;
	}
	else
		state->step -= mad_f_fromint(end - old);

	return newb - begin;
}
